﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.RegularExpressions;

using Biblio2.Models;
using Biblio2.Configuration;

namespace Biblio2.LocalParsing
{
    public class FileLister : BackgroundWorker
    {
        #region Constructeur
        public FileLister()
        {
            WorkerReportsProgress = true;
            WorkerSupportsCancellation = true;
        }
        #endregion Constructeur

        #region DoWork
        protected override void OnDoWork(DoWorkEventArgs e)
        {
            List<String> listFolders = ConfigurationManager.FilesConfiguration.FoldersList;
            List<PathPair> listResult = null;
            // Recherche de fichier
            if (listFolders != null)
                listResult = GetFiles(listFolders);

            // Exclusion des fichiers déjà traité
            
            if (listResult != null)
                ExcludeFileAlreadyInDb(ref listResult);

            if (listResult == null)
                e.Cancel = true;
            else
                e.Result = listResult;
        }
        #endregion DoWork

        #region GetFiles
        // Get the list of pathPair (Path + Filename) existing in the list of folders 
        public List<PathPair> GetFiles(List<String> listFolders)
        {
            List<PathPair> resultList = new List<PathPair>();
            int iCpt = 1;
            String sMsg = String.Empty;
            foreach (String sPath in listFolders)
            {
                if (CancellationPending)
                    return null;

                ReportProgress(0, new WorkerEventProgress(WorkerEventProgress.ReportEnum.Progress, LocalParsingManager.Step.Step1_1, iCpt, listFolders.Count, "- " + resultList.Count.ToString() + " épisodes trouvés."));

                if (!FilesInFolder(sPath, ref resultList, sPath.Length))
                    return null;
                
                iCpt++;
            }

            ReportProgress(0, new WorkerEventProgress(WorkerEventProgress.ReportEnum.Progress, LocalParsingManager.Step.Step1_1, iCpt - 1, listFolders.Count, "- " + resultList.Count.ToString() + " épisodes trouvés."));
            
            return resultList;
        }
        #endregion GetFiles

        #region ExcludeFiles
        private void ExcludeFileAlreadyInDb(ref List<PathPair> aList)
        {
            int iCpt = 0;

            for (int i = aList.Count - 1; i >= 0; i--)
            {
                ReportProgress(0, new WorkerEventProgress(WorkerEventProgress.ReportEnum.Progress, LocalParsingManager.Step.Step1_2, aList.Count - i, aList.Count, "- " + iCpt.ToString() + " nouveaux épisodes trouvés."));
                if (ModelManager.IsEpisodeInDB(aList[i]))
                    aList.RemoveAt(i);
                else
                    iCpt++;
            }
            ReportProgress(0, new WorkerEventProgress(WorkerEventProgress.ReportEnum.Progress, LocalParsingManager.Step.Step1_2, aList.Count, aList.Count, "- " + iCpt.ToString() + " nouveaux épisodes trouvés."));
        }

        #endregion
        #region FilesInFolder
        // List the PathPair existing in the folder using the regular expression
        private bool FilesInFolder(String aFolder, ref List<PathPair> aListPathPair, int anImportPathLength)
        {
            if (CancellationPending)
                return false;

            try
            {
                if (System.IO.Directory.Exists(aFolder))
                {
                    string[] sTabFiles = System.IO.Directory.GetFiles(aFolder, "*", System.IO.SearchOption.AllDirectories);
                    string sFilename = String.Empty;

                    if (sTabFiles != null)
                    {
                        foreach (string sFile in sTabFiles)
                        {
                            if (CancellationPending)
                                return false;

                            if (CheckFileExtension(sFile))
                            {
                                sFilename = sFile.Substring(sFile.LastIndexOf('\\')).TrimStart('\\');
                                aListPathPair.Add(new PathPair(sFilename, sFile.Remove(sFile.Length - sFilename.Length)));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                String sMsg = "Error occured while scanning files in '" + aFolder + "' (" + ex.Message + ") - Going folder by folder.";
                ReportProgress(0, new WorkerEventProgress(WorkerEventProgress.ReportEnum.Error, LocalParsingManager.Step.Step1_1, 0, 0, sMsg));

                // scan folder by folder by going recursive
                try
                {
                    foreach (string subDir in System.IO.Directory.GetDirectories(aFolder))
                    {
                        if (!FilesInFolder(subDir, ref aListPathPair, anImportPathLength))
                            return false;
                    }
                }
                catch (Exception)
                {
                    sMsg = "Inacessable folder: " + aFolder;
                    ReportProgress(0, new WorkerEventProgress(WorkerEventProgress.ReportEnum.Error, LocalParsingManager.Step.Step1_1, 0, 0, sMsg));
                    return false;
                }
            }

            return true;
        }
        #endregion FilesInFolder

        #region RegEx
        #region Attributs
        private static Regex m_regExprExtension = null;
        #endregion Attributs
        #region Methodes
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sFileName"></param>
        /// <returns></returns>
        private static bool CheckFileExtension(String sFileName)
        {
            if (m_regExprExtension == null)
                BuildExtRegex();

            return m_regExprExtension.IsMatch(System.IO.Path.GetExtension(sFileName));
        }

        /// <summary>
        /// 
        /// </summary>
        public static void BuildExtRegex()
        {
            String sExtPattern = String.Empty;

            List<String> listExtension = ConfigurationManager.FilesConfiguration.ExtensionsList;

            foreach (String ext in listExtension)
            {
                if (sExtPattern.Length > 0)
                    sExtPattern += '|';

                sExtPattern += ext.Replace(".", "\\.");
            }
            m_regExprExtension = new Regex(sExtPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }
        #endregion Methodes
        #endregion RegEx
    }
}
